package com.hbwxz.Cas;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * ABA问题
 * <p>
 * 比如说一个线程one从内存位置V中取出A，这时候另一个线程two也从内存中取出A，并且线程two进行了一些操作将值变成了B，
 * 然后线程two又将V位置的数据变成A，这时候线程one进行CAS操作发现内存中仍然是A，然后线程one操作成功。
 * <p>
 * CAS算法实现一个重要前提需要取出内存中某时刻的数据并在当下时刻比较并替换，那么在这个时间差类会导致数据的变化。
 * <p>
 * ABA问题总结：
 * 当线程A获取了原始值后a，此时因为CPU轮训机制或者其他因素导致线程A等待，**线程B拿到这个初始值a修改为b后又再次拿到b修改成了a，**此时线程a等待完成，发现初始值没有发生改变还是a，认为没有其他线程抢占。
 * 尽管线程one的CAS操作成功，但是不代表这个过程就是没有问题的。
 *
 * @author shenzw
 * @date 2023/12/20
 */
@Slf4j
public class ABADemo {

    public static void main(String[] args) throws InterruptedException {

        AtomicInteger atomicInteger = new AtomicInteger(100);
        ExecutorService executor = Executors.newFixedThreadPool(10);

        // 线程A拿到数据更改了值然后又重新设回之前的值
        executor.submit(() -> {
            atomicInteger.compareAndSet(100, 101);
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            atomicInteger.compareAndSet(101, 100);
        });

        // 主线程休眠3秒，模拟业务逻辑耗时
        TimeUnit.SECONDS.sleep(3);

        // 线程B获取值
        executor.submit(() -> log.info(Thread.currentThread().getName() + " 获取是否原值 = {}，结果 = {}", atomicInteger.compareAndSet(100, 2022), atomicInteger.get()));

        executor.shutdown(); // 线程池需要手动关闭
    }

}
